package com.naiterui.ehp.ps.sms.utils;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.BasicHttpEntity;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import lombok.extern.slf4j.Slf4j;

/**
 * Http请求工具类
 * <P>File name : HttpRequestUtils.java </P>
 * <P>Author : zhouyanxin </P>
 * <P>Date : 2015年6月28日 </P>
 */
@Slf4j
public final class HttpRequestUtils {

    /**
     * 请求超时时间
     */
    private static final int REQUEST_TIMEOUT = 5000;

    /**
     * 传输超时时间
     */
    private static final int TRANSFER_TIMEOUT = 5000;

    /**
     * 默认字符集
     */
    private static final String DEFAULT_CHARSET = "UTF-8";

    public static String doGet(String linkUrl) {
        HttpClient httpClient = HttpClients.createDefault();
        HttpGet getMethod = new HttpGet(linkUrl);
        RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(REQUEST_TIMEOUT).setConnectTimeout(TRANSFER_TIMEOUT).build();// 设置请求和传输超时时间
        getMethod.setConfig(requestConfig);
        try {
            HttpResponse response = httpClient.execute(getMethod);
            return EntityUtils.toString(response.getEntity(), DEFAULT_CHARSET).trim();
        } catch (Exception e) {
            log.error("http request error in doGet, linkUrl: {} ", linkUrl, e);
            return null;
        } finally {
            getMethod.abort();
            getMethod.releaseConnection();
        }
    }

    /**
     * POST请求
     * 对应StringEntity
     * HttpRequestUtils.doPost()<BR>
     * <P>Author : zhouyanxin </P>
     * <P>Date : 2015年6月28日 </P>
     *
     * @param linkUrl
     * @param param
     *
     * @return
     */
    public static String doPost(String linkUrl, String param) {
        HttpClient httpClient = HttpClients.createDefault();
        HttpPost request = new HttpPost(linkUrl);
        RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(REQUEST_TIMEOUT).setConnectTimeout(TRANSFER_TIMEOUT).build();// 设置请求和传输超时时间
        request.setConfig(requestConfig);
        try {
            StringEntity entity = new StringEntity(param, DEFAULT_CHARSET);
            request.setEntity(entity);
            HttpResponse response = httpClient.execute(request);
            return EntityUtils.toString(response.getEntity(), DEFAULT_CHARSET).trim();
        } catch (Exception e) {
            log.error("http request error in doPost, linkUrl: {} ", linkUrl, e);
            return null;
        } finally {
            request.abort();
            request.releaseConnection();
        }
    }

    /**
     * POST请求
     * 对应
     * HttpRequestUtils.doPost()<BR>
     * <P>Author : zhouyanxin </P>
     * <P>Date : 2015年6月28日 </P>
     *
     * @param linkUrl
     * @param params
     *
     * @return
     */
    public static String doPost(String linkUrl, Map<String, String> params) {

        // 构建请求参数
        List<BasicNameValuePair> formParams = new ArrayList<>();
        for (Entry<String, String> entry : params.entrySet()) {
            formParams.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
        }

        // 执行请求
        HttpClient httpClient = HttpClients.createDefault();
        HttpPost request = new HttpPost(linkUrl);
        RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(REQUEST_TIMEOUT).setConnectTimeout(TRANSFER_TIMEOUT).build();// 设置请求和传输超时时间
        request.setConfig(requestConfig);
        try {
            UrlEncodedFormEntity entity = new UrlEncodedFormEntity(formParams, DEFAULT_CHARSET);
            request.setEntity(entity);
            HttpResponse response = httpClient.execute(request);
            return EntityUtils.toString(response.getEntity(), DEFAULT_CHARSET).trim();
        } catch (Exception e) {
            log.error("http request error in doPost, linkUrl: {} ", linkUrl, e);
            return null;
        } finally {
            request.abort();
            request.releaseConnection();
        }
    }

    /**
     * 带header的post请求
     * HttpRequestUtils.doPostAndHeader()
     *
     * @param linkUrl
     * @param params
     * @param headers
     *
     * @return
     *
     * @Author chenlin
     * @Date 2016年11月7日
     * @since 1.0.0
     */
    public static String doPostAndHeader(String linkUrl, Map<String, String> params, Map<String, String> headers) {

        // 构建请求参数
        List<BasicNameValuePair> formParams = new ArrayList<>();
        for (Entry<String, String> entry : params.entrySet()) {
            formParams.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
        }

        // 执行请求
        HttpClient httpClient = HttpClients.createDefault();
        HttpPost request = new HttpPost(linkUrl);
        RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(REQUEST_TIMEOUT).setConnectTimeout(TRANSFER_TIMEOUT).build();// 设置请求和传输超时时间
        request.setConfig(requestConfig);
        Set<String> keySet = headers.keySet();
        for (String key : keySet) {
            request.setHeader(key, headers.get(key));
        }
        try {
            UrlEncodedFormEntity entity = new UrlEncodedFormEntity(formParams, DEFAULT_CHARSET);
            request.setEntity(entity);
            HttpResponse response = httpClient.execute(request);
            return EntityUtils.toString(response.getEntity(), DEFAULT_CHARSET).trim();
        } catch (Exception e) {
            log.error("http request error in doPostAndHeader, linkUrl: {} ", linkUrl, e);
            return null;
        } finally {
            request.abort();
            request.releaseConnection();
        }
    }

    /**
     * 流式传参、带header的post请求
     * HttpRequestUtils.doPostBasicAndHeader()
     *
     * @param linkUrl
     * @param requestBody
     * @param headers
     *
     * @return
     *
     * @Author
     * @Date 2017年7月26日
     * @since 1.0.0
     */
    public static String doPostBasicAndHeader(String linkUrl, String requestBody, Map<String, String> headers) {

        // 执行请求
        HttpClient httpClient = HttpClients.createDefault();
        HttpPost request = new HttpPost(linkUrl);
        RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(REQUEST_TIMEOUT).setConnectTimeout(TRANSFER_TIMEOUT).build();// 设置请求和传输超时时间
        request.setConfig(requestConfig);
        Set<String> keySet = headers.keySet();
        for (String key : keySet) {
            request.setHeader(key, headers.get(key));
        }
        try {
            BasicHttpEntity entity = new BasicHttpEntity();
            entity.setContent(new ByteArrayInputStream(requestBody.getBytes(DEFAULT_CHARSET)));
            entity.setContentLength(requestBody.getBytes(DEFAULT_CHARSET).length);
            request.setEntity(entity);
            HttpResponse response = httpClient.execute(request);
            return EntityUtils.toString(response.getEntity(), DEFAULT_CHARSET).trim();
        } catch (Exception e) {
            log.error("http request error in doPostBasicAndHeader, linkUrl: {} , requestBody: {}, headers: {}", linkUrl, requestBody, headers, e);
            return null;
        } finally {
            request.abort();
            request.releaseConnection();
        }
    }

    /**
     * doHttpURLRequest
     * doHttpURLRequest()
     *
     * @param url            请求地址
     * @param params         请求参数
     * @param method         请求方法
     * @param contentType    内容格式
     * @param connectTimeOut 连接服务超时时间
     * @param readTimeOut    读取返回结果超时时间
     *
     * @return
     *
     * @Author Ldl
     * @Date 2016年7月21日
     * @since 1.0.0
     */
    public static String doHttpURLRequest(String url, String params, String method, String contentType, int connectTimeOut, int readTimeOut) {
        URL realUrl;
        HttpURLConnection conn = null;
        PrintWriter writer = null;
        BufferedReader bufferReader = null;
        StringBuilder resultBuffer = new StringBuilder();
        try {
            realUrl = new URL(url);
            conn = (HttpURLConnection) realUrl.openConnection();
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setUseCaches(false);
            conn.setRequestMethod(method);
            conn.setConnectTimeout(connectTimeOut);// ConfigUtil.getInt("pay.connectTimeOut") == 0 ?
            // REQUEST_TIMEOUT :
            // ConfigUtil.getInt("pay.connectTimeOut")
            conn.setReadTimeout(readTimeOut);// ConfigUtil.getInt("pay.readTimeOut") == 0 ?
            // TRANSFER_TIMEOUT :
            // ConfigUtil.getInt("pay.readTimeOut")

            if (contentType == null) {
                contentType = "application/octet-stream";
            }
            conn.setRequestProperty("Content-Type", contentType);
            conn.setRequestProperty("Charset", DEFAULT_CHARSET);

            writer = new PrintWriter(conn.getOutputStream());
            writer.write(params);
            writer.flush();

            int responseCode = conn.getResponseCode();
            if (responseCode != 200) {
                log.error("服务返回结果失败,错误码:" + responseCode);
                return null;
            } else {
                bufferReader = new BufferedReader(new InputStreamReader(conn.getInputStream(), DEFAULT_CHARSET));
                String result = "";
                while ((result = bufferReader.readLine()) != null) {
                    resultBuffer.append(result);
                }
            }
            return resultBuffer.toString();
        } catch (Exception e) {
            log.error("请求服务异常", e);
            return null;
        } finally {
            if (conn != null) {
                conn.disconnect();
            }
            if (writer != null) {
                writer.close();
            }
            if (bufferReader != null) {
                try {
                    bufferReader.close();
                } catch (IOException e) {
                    log.error("http request error in doHttpURLRequest when bufferReader.close", e);
                }
            }
        }

    }

    /**
     * 模拟form表单的请求
     * HttpRequestUtils.doPostSendFile()
     *
     * @param linkUrl    请求地址
     * @param textMap    文本域值
     * @param fileUrlMap 文件访问于域名
     * @param headers    header参数值
     *
     * @return
     *
     * @Author chenlin
     * @Date 2016年10月13日
     * @since 1.0.0
     */
    public static String doPostSendFile(String linkUrl, Map<String, String[]> textMap, Map<String, String[]> fileUrlMap,
                                        Map<String, String> headers) {
        String res = "";
        HttpURLConnection conn = null;
        String boundary = "---------------------------"; // boundary就是request头和上传文件内容的分隔符
        try {
            URL url = new URL(linkUrl);
            conn = (HttpURLConnection) url.openConnection();
            conn.setConnectTimeout(5000);
            conn.setReadTimeout(30000);
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setUseCaches(false);
            conn.setRequestMethod("POST");
            conn.setRequestProperty("Connection", "Keep-Alive");
            conn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows; U; Windows NT 6.1; zh-CN; rv:1.9.2.6)");
            conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);

            Set<String> keySet = headers.keySet();
            for (String key : keySet) {
                conn.setRequestProperty(key, headers.get(key));
            }

            OutputStream out = new DataOutputStream(conn.getOutputStream());
            // text
            if (textMap != null) {
                StringBuilder strBuf = new StringBuilder();
                for (Entry<String, String[]> entry : textMap.entrySet()) {
                    String inputName = (String) entry.getKey();
                    String[] inputValue = (String[]) entry.getValue();
                    if (inputValue == null) {
                        continue;
                    }
                    for (String anInputValue : inputValue) {
                        if (StringUtils.isNotBlank(anInputValue)) {
                            strBuf.append("\r\n").append("--").append(boundary).append("\r\n");
                            strBuf.append("Content-Disposition: form-data; name=\"").append(inputName).append("\"\r\n\r\n");
                            strBuf.append(anInputValue);
                        }
                    }
                }
                out.write(strBuf.toString().getBytes());
            }

            // file
            if (fileUrlMap != null) {
                for (Entry<String, String[]> entry : fileUrlMap.entrySet()) {
                    String inputName = entry.getKey();
                    String[] inputValues = entry.getValue();
                    if (inputValues == null) {
                        continue;
                    }

                    for (String inputValue : inputValues) {
                        String fileName = inputValue.substring(inputValue.lastIndexOf("\\") + 1);
                        String strBuf = "\r\n" + "--" + boundary + "\r\n" + "Content-Disposition: form-data; name=\"" + inputName + "\"; filename=\""
                                + fileName + "\"\r\n" + "Content-Type:" + "image/jpeg" + "\r\n\r\n";
                        out.write(strBuf.getBytes());

                        URL imgURL = new URL(inputValue);
                        DataInputStream in = new DataInputStream(imgURL.openStream());
                        int bytes = 0;
                        byte[] bufferOut = new byte[1024];
                        while ((bytes = in.read(bufferOut)) != -1) {
                            out.write(bufferOut, 0, bytes);
                        }
                        in.close();
                    }
                }
            }

            byte[] endData = ("\r\n--" + boundary + "--\r\n").getBytes();
            out.write(endData);
            out.flush();
            out.close();

            // 读取返回数据
            StringBuilder strBuf = new StringBuilder();
            if (conn.getResponseCode() != 200) {
                log.error("发送POST请求出错。" + linkUrl);
                return null;
            }
            BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
            String line = null;
            while ((line = reader.readLine()) != null) {
                strBuf.append(line).append("\n");
            }
            res = strBuf.toString();
            reader.close();
            reader = null;
        } catch (Exception e) {
            log.error("发送POST请求出错。{}", linkUrl, e);
        } finally {
            if (conn != null) {
                conn.disconnect();
            }
        }
        return res;
    }

}
